package com.lc.communication.service;


import cn.hutool.core.lang.UUID;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.log.Log;
import com.lc.communication.constants.ChannelConstant;
import com.lc.communication.handle.HeartBeatClientHandler;
import com.lc.communication.handle.MyMessageDecoder;
import com.lc.communication.handle.MyMessageEncoder;
import com.lc.communication.listener.ConnectionListener;
import com.lc.communication.util.ChannelMap;
import com.lc.communication.vo.RequestVo;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

//客户端代码
public class HeartBeatClient {
    private static final Log log = Log.get();

    public static void main(String[] args) throws Exception {
        HeartBeatClient.start("client_a", "127.0.0.1", 8888);
    }

    public static void start(String clientName, String ip, int port) {
        //String clientName ="client_a";
        String uuid = UUID.randomUUID().toString();
        ChannelMap.CLIENT_NAME_UUID.put(clientName, uuid);
        Connection.connect(clientName, uuid, ip, port);
    }

    public static class Connection {
        private static final AtomicInteger connectIndex = new AtomicInteger(0);

        public static void connect(String clientName, String uuid, String ip, int port) {
            EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
            try {
                Bootstrap bootstrap = new Bootstrap();
                bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
                        .handler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ChannelPipeline pipeline = ch.pipeline();
                                pipeline.addLast("decoder", new MyMessageDecoder());
                                pipeline.addLast("encoder", new MyMessageEncoder());
                                pipeline.addLast(new HeartBeatClientHandler(clientName, uuid, ip, port));
                            }
                        });

                log.info("netty client start。。");
                ChannelFuture channelFuture = bootstrap.connect(ip, port).sync();

                //心跳
                channelHeart(uuid, clientName,channelFuture.channel());

                // 添加监听后 如果连接中断会调用GenericFutureListener中operationComplete方法（子类实现）
                channelFuture.addListener(new ConnectionListener(clientName, uuid, ip, port));
            } catch (Exception e) {
                if (connectIndex.get() < ChannelConstant.CONNECT_INDEX) {
                    log.warn("链接失败:{} ," + (ChannelConstant.SERVER_HEART_TIME / 1000) + "s 后重新连接。。。", e.getMessage());
                    ThreadUtil.sleep(ChannelConstant.SERVER_HEART_TIME);
                    Connection.connect(clientName, uuid, ip, port);
                } else {
                    log.error("链接失败:{} ", e.getMessage());
                }
                connectIndex.addAndGet(1);
            } finally {
                eventLoopGroup.shutdownGracefully();
            }
        }

    }

    public static void channelHeart(String uuid, String clientName,Channel channel) {
        Random random = new Random();
        while (channel.isActive()) {
            if (!ChannelMap.CHANNEL_SERVER_MAP.containsKey(uuid)) {
                //给服务端发消息通道
                //System.out.println(clientName);
                ChannelMap.CHANNEL_SERVER_MAP.put(uuid, channel);
                RequestVo requestVo = new RequestVo();
                requestVo.setId(UUID.randomUUID().toString());
                requestVo.setClientName(clientName);
                requestVo.setType(ChannelConstant.CLIENT_LINK_SUCCESS);
                requestVo.setClientUuid(uuid);
                requestVo.setBody("让客户端记录服务端通道");
                //发送服务端消息，记录成对通道
                channel.writeAndFlush(requestVo.toRequestVo());
            }
            int num = random.nextInt(10) * ChannelConstant.SERVER_HEART_TIME / 1000;
            ThreadUtil.sleep(num * 1000);
            //这个通道 接收方 是服务端
            channel.writeAndFlush(getHeartbeatPacketVo(clientName, uuid).toRequestVo());
        }
    }


    public static RequestVo getHeartbeatPacketVo(String clientName, String uuid) {
        RequestVo requestVo = new RequestVo();
        requestVo.setId(UUID.randomUUID().toString());
        requestVo.setType(ChannelConstant.TYPE_HEART);
        requestVo.setClientName(clientName);
        requestVo.setClientUuid(uuid);
        requestVo.setBody("client dong dong dong...");
        return requestVo;
    }

}

